home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <string.h>
- #include <conio.h>
- #include <dos.h>
-
- #include "boolean.h"
- #include "vga.h"
-
- //#define VSYNC_MONITOR // This puts a bar graph on the screen that shows
- // how much time is being spent waiting for
- // vertical retrace.
-
- char * const screen_lin_addr = (char *) 0xA0000;
-
- const video_int = 0x10; // Video interrupt number
- const sequ_addr = 0x3c4; // Base port of Sequencer
- const crtc_addr = 0x3d4; // Base port of CRT Controller
- const input_status_1 = 0x3da; // Input Status 1 register
-
- const screen_width = 320;
- const screen_height = 200;
- const bytes_per_row = 80;
-
- //----------------------------------------------------------------------------
-
- // These values contain the high byte of the page's offset in display memory,
- // along with the byte 0x0C, which indicates to the CRT Controller that we
- // are setting the high byte of the display offset.
- //
- // Note that the low byte of the display page is not changed.
-
- static int v_page_nr = 0x000C;
- static int a_page_nr = 0x3f0C;
-
- // The addresses of the active and visible screen pages.
-
- char * v_page = screen_lin_addr + 0x0000;
- char * a_page = screen_lin_addr + 0x3f00;
-
- // The saved screen mode number.
-
- static int old_mode_nr;
-
- // Edge arrays.
-
- static int edge_l [ screen_height ];
- static int edge_r [ screen_height ];
-
- //----------------------------------------------------------------------------
- // The VGA object. (Only one is allowed.)
- //----------------------------------------------------------------------------
-
- vga_t vga;
-
- //----------------------------------------------------------------------------
- // FUNCTION swap
- //----------------------------------------------------------------------------
-
- inline void swap
- (
- int& var1,
- int& var2
- )
- {
- int temp;
-
- temp = var1;
- var1 = var2;
- var2 = temp;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION draw_scanlines
- //----------------------------------------------------------------------------
- // Draws the scan lines from y1 to y2, using the X coordinates stored in the
- // edge_l and edge_r arrays.
- //----------------------------------------------------------------------------
-
- static int l_clip_plane_mask [] = { 0x0F02, 0x0E02, 0x0C02, 0x0802 };
- static int r_clip_plane_mask [] = { 0x0102, 0x0302, 0x0702, 0x0F02 };
-
- inline void draw_scanlines
- (
- int y1,
- int y2,
- int color
- )
- {
- char * row_addr = a_page + (y1 * bytes_per_row);
-
- for ( int i = y1; i <= y2; ++ i )
- {
- int x1 = edge_l [i];
- int x2 = edge_r [i];
-
- if ( x2 < x1 )
- {
- continue;
- }
-
- char * first_byte_addr = row_addr + x1 / 4;
- char * last_byte_addr = row_addr + x2 / 4;
-
- int l_clip = l_clip_plane_mask [x1 & 3];
- int r_clip = r_clip_plane_mask [x2 & 3];
-
- if ( first_byte_addr == last_byte_addr )
- {
- l_clip &= r_clip;
-
- outpw ( sequ_addr, l_clip );
-
- *first_byte_addr = (char) color;
- }
- else
- {
- // Draw the first byte.
-
- outpw ( sequ_addr, l_clip );
-
- *first_byte_addr = (char) color;
-
- ++ first_byte_addr;
-
- // Draw the middle bytes.
-
- outpw ( sequ_addr, 0x0F02 );
-
- memset ( first_byte_addr, color, last_byte_addr-first_byte_addr );
-
- // Draw the last byte.
-
- outpw ( sequ_addr, r_clip );
-
- *last_byte_addr = (char) color;
- }
-
- row_addr += bytes_per_row;
- }
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::exists
- //----------------------------------------------------------------------------
- // Checks to see if there is a VGA display adapter. Returns true if there
- // is, false if there isn't.
- //----------------------------------------------------------------------------
-
- boolean vga_t::exists
- (
- void
- )
- {
- boolean exists;
- union REGS regs;
-
- regs.h.ah = 0x1A;
- regs.h.al = 0;
-
- int386 ( video_int, & regs, & regs );
-
- if ( regs.h.al == 0x1A )
- exists = true;
- else
- exists = false;
-
- return exists;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::start
- //----------------------------------------------------------------------------
- // Saves the current video mode and switches to mode 13h.
- //----------------------------------------------------------------------------
-
- void vga_t::start ( void )
- {
- union REGS regs;
-
- // Get information about the current video state.
-
- regs.h.ah = 0x0f;
- int386 ( video_int, & regs, & regs );
- old_mode_nr = regs.h.al;
-
- // Start with normal 320x200x256 mode.
-
- regs.x.eax = 0x13;
- int386 ( video_int, & regs, & regs );
-
- // Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4).
-
- outpw ( sequ_addr, 0x0604 );
-
- // Turn off word mode, by setting the Mode Control Register of the
- // CRT Controller (index 0x17, port 0x3d4).
-
- outpw ( crtc_addr, 0xE317 );
-
- // turn off doubleword mode, by setting the Underline Location register
- // (index 0x14, port 0x3d4).
-
- outpw ( crtc_addr, 0x0014 );
-
- // Select all four planes for output.
-
- outpw ( sequ_addr, 0x0F02 );
-
- // Clear display memory to zeroes.
-
- memset ( screen_lin_addr, 0, 0x10000 );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::end
- //----------------------------------------------------------------------------
- // Restores the previous video mode.
- //----------------------------------------------------------------------------
-
- void vga_t::end
- (
- void
- )
- {
- union REGS regs;
-
- regs.x.eax = old_mode_nr;
-
- int386 ( video_int, & regs, & regs );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::clear
- //----------------------------------------------------------------------------
- // Fills the entire screen buffer with the given color.
- //----------------------------------------------------------------------------
-
- void vga_t::clear
- (
- int color
- )
- {
- // Enable writes to all four planes.
-
- outpw ( sequ_addr, 0x0F02 );
-
- // Clear the active page.
-
- memset ( a_page, color, bytes_per_row * screen_height );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::update
- //----------------------------------------------------------------------------
- // Copies the drawing buffer into screen memory.
- //----------------------------------------------------------------------------
-
- void vga_t::update
- (
- void
- )
- {
- // Swap the visible and active pages.
-
- {
- int temp = v_page_nr;
- v_page_nr = a_page_nr;
- a_page_nr = temp;
- }
-
- {
- char * temp = v_page;
- v_page = a_page;
- a_page = temp;
- }
-
- // Output the Change Display Offset High byte, along with the high byte of
- // the new display offset.
-
- outpw ( crtc_addr, v_page_nr );
-
- // Now wait for vertical sync, so the active page will be invisible when
- // we start drawing to it.
-
- #ifdef VSYNC_MONITOR
- char * p = v_page;
- int counter = 0;
-
- outpw ( sequ_addr, 0x0F02 );
- #endif
-
- while ( (inp (input_status_1) & 8) != 0 )
- ;
-
- while ( (inp (input_status_1) & 8) == 0 )
- {
- // Do nothing.
-
- #ifdef VSYNC_MONITOR
- ++ counter;
- if ( counter >= 128 )
- {
- counter = 0;
- *p = 255;
- p += bytes_per_row-1;
- *p = 255;
- ++ p;
- }
- #endif
- }
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::resize
- //----------------------------------------------------------------------------
- // Resizes the clipping window to the given coordinates.
- //----------------------------------------------------------------------------
-
- void win_t::resize
- (
- int new_x1,
- int new_y1,
- int new_x2,
- int new_y2
- )
- {
- x1 = new_x1;
- y1 = new_y1;
- x2 = new_x2;
- y2 = new_y2;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::clear
- //----------------------------------------------------------------------------
- // Fills a window with the given color.
- //----------------------------------------------------------------------------
-
- void win_t::clear
- (
- int color
- )
- {
- int y;
-
- // Scan convert the window.
-
- for ( y = y1; y < y2; ++ y )
- {
- edge_l [y] = x1;
- edge_r [y] = x2-1;
- }
-
- // Fill the window.
-
- draw_scanlines ( y1, y2-1, color );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::point
- //----------------------------------------------------------------------------
- // Draws a point that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::point
- (
- int x,
- int y,
- int color
- )
- {
- if ( x >= x1 && x < x2 && y >= y1 && y < y2 )
- {
- outp ( sequ_addr, 0x02 );
- outp ( sequ_addr+1, 0x01 << (x & 3) );
-
- a_page [ bytes_per_row*y + (x / 4) ] = (char) color;
- }
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::rect
- //----------------------------------------------------------------------------
- // Draws a filled rectangle that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::rect
- (
- int rect_x1,
- int rect_y1,
- int rect_x2,
- int rect_y2,
- int color
- )
- {
- int y;
-
- // Clip the rectangle to the viewing window.
-
- if ( rect_x2 < x1 || rect_x1 >= x2 ||
- rect_y2 < y1 || rect_y1 >= y2 )
- goto exit_func;
-
- if ( rect_x1 < x1 )
- rect_x1 = x1;
-
- if ( rect_x2 > x2 )
- rect_x2 = x2;
-
- if ( rect_y1 < y1 )
- rect_y1 = y1;
-
- if ( rect_y2 > y2 )
- rect_y2 = y2;
-
- // Scan convert the rectangle.
-
- rect_x2 -= 1;
- rect_y2 -= 1;
-
- for ( y = rect_y1; y <= rect_y2; ++ y )
- {
- edge_l [y] = rect_x1;
- edge_r [y] = rect_x2;
- }
-
- // Draw!
-
- draw_scanlines ( rect_y1, rect_y2, color );
-
- exit_func:
-
- return;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::line
- //----------------------------------------------------------------------------
- // Draws a line that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::line
- (
- int line_x1,
- int line_y1,
- int line_x2,
- int line_y2,
- int color
- )
- {
- int delta_x;
- int delta_y;
-
- // Switch the points so that (line_x1,line_y1) is always the top one.
-
- if ( line_y2 < line_y1 )
- {
- swap ( line_x1, line_x2 );
- swap ( line_y1, line_y2 );
- }
-
- // Compute the x and y deltas.
-
- delta_x = line_x2 - line_x1;
- delta_y = line_y2 - line_y1;
-
- // Clip the line on the left and right edges.
-
- if ( line_x1 < x1 )
- {
- if ( line_x2 < x1 ) goto exit_func;
-
- line_y1 += ( delta_y * ( x1 - line_x1 ) / delta_x );
- line_x1 = x1;
- }
- else if ( line_x1 >= x2 )
- {
- if ( line_x2 >= x2 ) goto exit_func;
-
- line_y1 += ( delta_y * ( x2 - line_x1 ) / delta_x );
- line_x1 = x2 - 1;
- }
-
- if ( line_x2 < x1 )
- {
- line_y2 += ( delta_y * ( x1 - line_x2 ) / delta_x );
- line_x2 = x1;
- }
- else if ( line_x2 >= x2 )
- {
- line_y2 += ( delta_y * ( x2 - line_x2 ) / delta_x );
- line_x2 = x2 - 1;
- }
-
- // Don't draw lines that are completely off the screen.
-
- if ( line_y2 < y1 || line_y1 >= y2 ) goto exit_func;
-
- // Clip the line on the top edge.
-
- if ( line_y1 < y1 )
- {
- line_x1 += ( delta_x * ( y1 - line_y1 ) / delta_y );
- line_y1 = y1;
-
- if ( line_x1 < x1 ) line_x1 = x1;
- if ( line_x1 >= x2 ) line_x1 = x2 - 1;
- }
-
- // Clip the line on the bottom edge.
-
- if ( line_y2 >= y2 )
- {
- line_x2 += ( delta_x * ( y2 - line_y2 ) / delta_y );
- line_y2 = y2 - 1;
-
- if ( line_x2 < x1 ) line_x2 = x1;
- if ( line_x2 >= x2 ) line_x2 = x2 - 1;
- }
-
- // Recompute the x and y deltas using the clipped coordinates.
-
- delta_x = line_x2 - line_x1;
- delta_y = line_y2 - line_y1;
-
- // Draw the line.
-
- {
- int denominator;
- int nr_pixels;
- int frac_x;
- int frac_y;
- int add_x;
- const int add_y = 1;
-
-
- if (delta_x > 0)
- {
- add_x = 1;
- }
- else
- {
- add_x = -1;
- delta_x = -delta_x;
- }
-
- if ( delta_y > delta_x )
- {
- denominator = delta_y;
- nr_pixels = delta_y + 1;
- }
- else
- {
- denominator = delta_x;
- nr_pixels = delta_x + 1;
- }
-
- frac_y = frac_x = denominator >> 1;
-
- for ( ; nr_pixels > 0; -- nr_pixels )
- {
- point ( line_x1, line_y1, color );
-
- frac_x += delta_x;
-
- if ( frac_x > denominator )
- {
- frac_x -= denominator;
- line_x1 += add_x;
- }
-
- frac_y += delta_y;
-
- if ( frac_y > denominator )
- {
- frac_y -= denominator;
- line_y1 += add_y;
- }
- }
- }
-
- exit_func:
-
- return;
- }
-
-